﻿
Imports System.Drawing
Imports System.Net
Imports std
Imports storoomc
Imports avacom
Imports graphUtils

Public Class portrait
    Inherits cacheProcessor

    Public Const storoomKeyPrefix As String = "avatar.portrait."
    Public Const resizeContentType As String = network.http.contentType.imagejpeg
    Private Shared tp As threadpool = Nothing

    Private Class tpjob
        Public url As String
        Public b As bytes
        Public ct As String

        Public Sub New(ByVal url As String, ByVal b As bytes, ByVal ct As String)
            Me.url = url
            Me.b = b
            Me.ct = ct
        End Sub
    End Class

    Private Class defaultImageProcessor
        Inherits staticrequest

        Public Const defaultImageFilename As String = "defimg.png"

        Protected Overrides Function filename(ByVal context As httpContext) As String
            Return defaultImageFilename
        End Function
    End Class

    Private Shared defaultImage As defaultImageProcessor = Nothing

    Private Shared Sub writeCache(ByVal i As tpjob)
        assert(Not i Is Nothing)
        storoom.write(contentStoroomKey(i.url), i.b)
        storoom.write(contentTypeStoroomKey(i.url), encoding.utf8().GetBytes(i.ct))
    End Sub

    Private Shared Sub writeCache(ByVal input As Object)
        writeCache(convertor.cast(Of tpjob)(input))
    End Sub

    Private Shared Sub shutdownTP()
        If Not tp Is Nothing Then
            tp.stop()
            tp = Nothing
        End If
    End Sub

    Shared Sub New()
        defaultImage = New defaultImageProcessor()
        tp = New threadpool(AddressOf writeCache, 4)
        AddHandler applicationShutdown, AddressOf shutdownTP
    End Sub

    Public Overrides Function pathidentity() As String
        Return path.portrait
    End Function

    Protected Overrides Function cookieName() As String
        Return "portrait"
    End Function

    Private Shared Function contentStoroomKey(ByVal url As String) As String
        Return storoomKeyPrefix + url
    End Function

    Public Shared Function contentTypeStoroomKey(ByVal url As String) As String
        Return storoomKeyPrefix + url + ".contentType"
    End Function

    Private Shared Function imageContentType(ByVal url As String, ByRef contentType As String) As Boolean
        Dim ctb As bytes = Nothing
        If storoom.read(contentTypeStoroomKey(url), ctb) Then
            contentType = encoding.utf8().GetString(+ctb)
            Return True
        Else
            Return False
        End If
    End Function

    Private Shared Function downloadImage(ByVal url As String, ByRef b As bytes, ByRef contentType As String) As Boolean
        If storoom.read(contentStoroomKey(url), b) AndAlso imageContentType(url, contentType) Then
            Return True
        Else
            Dim response As HttpWebResponse = Nothing
            If requestHttpWeb(url, response, timeoutMS:=httpProxy.defaultHoldtime) Then
                If b Is Nothing Then
                    b = New bytes()
                Else
                    b.clear()
                End If
                b.size() = response.ContentLength()
                Dim stream As IO.Stream = Nothing
                stream = response.GetResponseStream()
                Dim rtn As Boolean = False
                If readstream(stream, b, length:=b.size(), holdtime:=httpProxy.defaultHoldtime) = b.size() Then
                    contentType = response.ContentType()
                    tp.insertJob(New tpjob(url, b, contentType))
                    rtn = True
                Else
                    rtn = False
                End If
                closestream(stream)
                response.Close()
                Return rtn
            Else
                Return False
            End If
        End If
    End Function

    Private Shared Function serveProxy(ByVal context As httpContext, ByVal value As String) As Boolean
        Dim b As bytes = Nothing
        Dim ct As String = Nothing
        If downloadImage(value, b, ct) Then
            context.buff().Write(+b, 0, b.size())
            context.setcontentType(ct)
            Return True
        Else
            Return False
        End If
    End Function

    Private Shared Function serveProxyWithResize(ByVal context As httpContext, ByVal value As String,
                                                 ByVal width As Int64, ByVal height As Int64) As Boolean
        Dim b As bytes = Nothing
        If downloadImage(value, b, Nothing) Then
            Dim s As IO.MemoryStream = Nothing
            s = New IO.MemoryStream(+b)
            Dim img As Image = Nothing
            img = New Bitmap(s)
            Dim img2 As Image = Nothing
            img2 = resizeImage(img, New Size(width, height))
            img.Dispose()
            If img2 Is Nothing Then
                Return False
            Else
                context.setcontentType(resizeContentType)
                img2.Save(context.buff(), Imaging.ImageFormat.Jpeg)
                img2.Dispose()
                Return True
            End If
        Else
            Return False
        End If
    End Function

    Private Shared Function serveRedirect(ByVal context As httpContext, ByVal value As String) As Boolean
        Return context.redirect(value)
    End Function

    Private Shared Function processDefaultImage(ByVal context As httpContext) As Boolean
        Return defaultImage.process(context)
    End Function

    Private Shared Function _process(ByVal context As httpContext,
                                     ByVal id As String,
                                     ByVal value As String,
                                     ByVal format As String) As Boolean
        assert(Not isemptystring(value) AndAlso availableHttpAddress(value))
        If strsame(format, avacom.format.redirect, False) Then
            Return serveRedirect(context, value)
        Else
            Dim width As Int64 = 0
            Dim height As Int64 = 0
            If parseSize(context, width, height) Then
                Return serveProxyWithResize(context, value, width, height)
            Else
                Return serveProxy(context, value)
            End If
        End If
    End Function

#If RETIRED Then
    Protected Overrides Sub addresponseHeaders(ByVal context As httpContext,
                                               ByVal value As String,
                                               ByVal format As String)
        If isemptystring(context.response().ContentType()) Then
            If parseSize(context, Nothing, Nothing) Then
                'with resize, always be jpeg
                context.setcontentType(resizeContentType)
            Else
                Dim ct As String = Nothing
                If imageContentType(value, ct) Then
                    context.setcontentType(ct)
                ElseIf downloadImage(value, Nothing, ct) Then
                    'if no content type in cache, can only download it again
                    context.setcontentType(ct)
                Else
                    'when following situation, can go to here
                    '1. this response is cached
                    '2. the storoom.cache has been cleared
                    '3. the image cannot be downloaded again
                    context.setcontentType(network.http.contentType.image)
                End If
            End If
        End If
    End Sub
#End If

    Protected Overloads Overrides Function process(ByVal context As httpContext,
                                                   ByVal id As String,
                                                   ByVal value As String,
                                                   ByVal format As String) As Boolean
        If isemptystring(value) OrElse Not availableHttpAddress(value) Then
            Return processDefaultImage(context)
        ElseIf Not _process(context, id, value, format) Then
            Return processDefaultImage(context)
        Else
            Return True
        End If
    End Function
End Class

#If RETIRED Then
Public Class portraitProxy
    Inherits httpProxy

    Protected Overrides Function create() As Boolean
        If MyBase.create() Then
            FDRequest.removeheaders(request)
            Return True
        Else
            Return False
        End If
    End Function
End Class

Public Class portraitProxyPool_t
    Inherits httpProxyPool_t

    Protected Overrides Function create() As httpProxy
        Return New portraitProxy()
    End Function
End Class

Public Module _portraitProxyPool
    Private _portraitProxyPool As portraitProxyPool_t = Nothing

    Sub New()
        _portraitProxyPool = New portraitProxyPool_t()
    End Sub

    Public Function proxypool() As portraitProxyPool_t
        Return _portraitProxyPool
    End Function
End Module
#End If
